﻿


#include "ExcelUnit.h"
#include "../Misc/StringOperate.h"
#include "../Misc/CmnFunc.h"
#include "../Misc/File.h"
#include "../CommonDef.h"
#include "../TinyXml/tinyxml.h"

dn_namespace_beg

namespace
{
	enum
	{
		col_type_null,
		col_type_int,
		col_type_float,
		col_type_text,
		col_type_real,
		col_type_vint,
		col_type_vfloat,
		col_type_vtext,
		col_type_vreal,
	};


	std::string GetPath(const std::string& ExeDir,const std::string& ExdPath,const std::string& FilePath)
	{
		std::string TempPath("");
		TempPath.append(ExeDir);
		TempPath.append(ExdPath);
		TempPath.append(FilePath);

		std::string::iterator LastDiagonalIt = TempPath.begin();

		std::string::iterator it = TempPath.begin();
		std::string::iterator it_end = TempPath.end();

		for(;it!=it_end;it++)
		{
			if(*it=='\\')
				LastDiagonalIt = it;
		}
		LastDiagonalIt++;

		std::string Path("");
		it = TempPath.begin();
		for(;it!=LastDiagonalIt;it++)
		{
			Path.push_back(*it);
		}

		return Path;
	}

}


//-----------------------------------------ExcleLine------------------------------------------------

namespace 
{
	char* GetValue(ExcelLine* pLine,int Col,int ArrayCol)
	{
		char* Value = 0;

		std::map<uint32, std::vector<char*>*>::iterator DataIt = ((pLine->ArrayData).find(Col));
		if(DataIt!=pLine->ArrayData.end())
		{
			std::vector<char*>* ArrayData =  DataIt->second;
			if(ArrayCol<(int)ArrayData->size())
			{
				Value = (*ArrayData)[ArrayCol];
			}
			else
			{
				//log
			}
		}

		return Value;
	}

	char* GetValue(ExcelLine* pLine,int Col)
	{
		char* Value = 0;

		std::map<uint32, char*>::iterator DataIt = ((pLine->SingleData).find(Col));
		if(DataIt!=pLine->SingleData.end())
		{
			Value =  DataIt->second;
		}

		return Value;
	}

	bool TestColType(ExcelLine* pLine,int Col, int OughtType)
	{
		if(pLine->pTable)	
		{
			int Type = pLine->pTable->LineInfo.TypeInfo[Col];
			if(OughtType == Type) 
			{
				return true;
			}
			else
			{
				if(Type==col_type_real &&( OughtType==col_type_int|| OughtType==col_type_float||OughtType==col_type_text))
				{
					return true;
				}
				else if(Type==col_type_vreal &&( OughtType==col_type_vint|| OughtType==col_type_vfloat||OughtType==col_type_vtext))
				{
					return true;
				}
			}
		}

		return false;
	}

}


ExcelLine::ExcelLine()
{
	ID= 0; 
}

ExcelLine::ExcelLine(ExcelTable* pT,int idx)
{
	pTable=pT;
	ID=0;
	Index = idx;
}


ExcelLine::~ExcelLine()
{

}


bool ExcelLine::GetInt(int Col,int& Output)
{
	if(!TestColType(this,Col, col_type_int))
	{
		//log
		return false;
	}

	char* data;
	data = GetValue(this, Col);
	if(data == 0 || strcmp(data,"")==0)
	{
		Output=0;
	}
	else
	{
		Output = atoi(data);
	}

	return true;
}


bool ExcelLine::GetFloat(int Col,float& Output)
{
	if(!TestColType(this,Col, col_type_float))
	{
		//log
		return false;
	}

	char* data;
	data = GetValue(this, Col);
	if(data == 0 || strcmp(data,"")==0)
	{
		Output=0.0f;
	}
	else
	{
		Output = (float)atof(data);
	}

	return true;

}


bool ExcelLine::GetStr(int Col,std::string& Output)
{
	if(!TestColType(this,Col, col_type_text))
	{
		//log
		return false;
	}

	char* data;
	data = GetValue(this, Col);
	if(data != 0 && strcmp(data,"")!=0)
	{
		Output=data;
	}

	return true;

}

bool ExcelLine::GetArrayInt(int Col,std::vector<int>& Output )
{
	if(!TestColType(this,Col, col_type_vint))
	{
		//log
		return false;
	}
	
	int	Size = GetArraySize(Col);
	for(int i=0; i<Size; i++)
	{
		char* data;
		int OutputInt;
		data = GetValue(this, Col, i);
		if(data == 0 || strcmp(data,"")==0)
		{
			OutputInt=0;
		}
		else
		{
			OutputInt = atoi(data);
		}

		Output.push_back(OutputInt);
	}

	return true;
}


bool ExcelLine::GetArrayFloat(int Col,std::vector<float>& Output)
{
	if(!TestColType(this,Col, col_type_vfloat))
	{
		//log
		return false;
	}

	int	Size = GetArraySize(Col);
	for(int i=0; i<Size; i++)
	{
		char* data;
		float OutputInt;
		data = GetValue(this, Col, i);
		if(data == 0 || strcmp(data,"")==0)
		{
			OutputInt=0;
		}
		else
		{
			OutputInt = (float)atof(data);
		}

		Output.push_back(OutputInt);
	}

	return true;

}


bool ExcelLine::GetArrayStr(int Col,std::vector<std::string>& Output)
{
	if(!TestColType(this,Col, col_type_vtext))
	{
		//log
		return false;
	}

	int	Size = GetArraySize(Col);
	for(int i=0; i<Size; i++)
	{
		char* data = GetValue(this, Col, i);
		Output.push_back(data);
	}

	return true;
}

int	ExcelLine::GetArraySize(int Col)
{
	std::map<uint32, std::vector<char*>* >::iterator DataIt = ArrayData.find(Col);
	if(DataIt==ArrayData.end())
	{
		return 0;
	}

	return (int)(DataIt->second)->size();


}


//------------------------------ExcelTable-------------------------------------------
namespace
{

	bool IsSingleCol(int Col,ExcelLine* pLine)//��һ���Ƿ�Ϊ��һ����
	{
		ExcelTable* pTable = pLine->pTable;
		int Type = pTable->LineInfo.TypeInfo[Col];
		if(Type==col_type_int ||Type==col_type_float||Type==col_type_text||Type==col_type_real)
		{
			return true;
		}

		return false;
	}

	bool GetFileLimit(TiXmlElement* FileElement, uint32& Top, uint32& Bottom)
	{
		const char* LimitText = FileElement->Attribute("limit");
		if(!LimitText)	return false;

		std::string szTop;
		std::string szBottom;

		std::string szLimit(LimitText);
		std::string::iterator it	 = szLimit.begin();
		std::string::iterator it_end = szLimit.end();
		bool GetingTop = true;
		for(;it!=it_end;it++)
		{
			if(*it == ',')
			{
				if(GetingTop)
				{
					GetingTop = false;
					continue;
				}
				else
				{
					break;
				}
			}

			if(GetingTop)
				szTop.push_back(*it);
			else
				szBottom.push_back(*it);
		}

		if(szTop.empty())	
		{
			//log 
			return false;
		}

		if(szBottom.empty())
		{
			//log 
			return false;
		}

		Top		= (uint32)atoi(szTop.c_str());
		Bottom  = (uint32)atoi(szBottom.c_str());

		return true;
	}

	void NormalizeStr(std::string* InputStr)
	{
		if(InputStr->empty())
			return;

		std::string::iterator it = InputStr->begin();
		std::string::iterator it_end = InputStr->end();
		it_end--;

		if(*it == L'\"' && *it == *it_end)
		{
			std::string::iterator str_begin = InputStr->begin();
			InputStr->erase(str_begin);

			std::string::iterator str_end = InputStr->end();
			str_end--;
			InputStr->erase(str_end);
		}


	}

	void LinePushData(char* Data,int DataSize,int& Col,ExcelLine* pLine)
	{
		ExcelTable* pTable = pLine->pTable;

		if(pTable->LineInfo.KeyCol == Col)
		{
			if(IsSingleCol(Col,pLine))//only the single data can be the key col
			{
				pLine->ID = atoi(Data);
			}
		}

		if(!pTable->LineInfo.IsLoad[Col]) return;

		if(IsSingleCol(Col,pLine))
		{
			pLine->SingleData.insert( std::pair<uint32, char*>(Col,Data) );
			//pLine->SingleData[Col] = Data;
		}
		else
		{
			std::vector<char*>* ArrayData = new std::vector<char*>;

			int BeginCount = 0;
			int i = 0;
			for(;i!=DataSize;i++)
			{
				if(Data[i] == L'*')
				{
					if(i-BeginCount>=0)
					{
						Data[i]=L'\0';
						if(strcmp(Data+BeginCount, "") != 0)
						{
							ArrayData->push_back(Data+BeginCount);
						}
						BeginCount = i+1;
					}
				}
			}

			if(BeginCount!= i)
			{
				if(strcmp(Data+BeginCount, "") != 0)
				{
					ArrayData->push_back(Data+BeginCount);
				}
			}

			pLine->ArrayData.insert(std::pair< uint32,std::vector<char*>*>(Col,ArrayData));
			//pLine->ArrayData[Col] = ArrayData;
		}

	}

	bool GetLine(FILE   *fp,ExcelLine* pLine)
	{
		int ColCountMax = (int)pLine->pTable->LineInfo.TypeInfo.size();

		const int ReadMax = 1024;		
		char*  CharArry = new char[ReadMax]; 

		int	  Col = 0;
		char* TempStr = 0;
		int TempStrSize = 0;
		while(!feof(fp))
		{
			if(fgets(CharArry,ReadMax,fp)!=NULL)
			{
				int StrBeginCount = 0;
				for(int i=0;i<ReadMax;i++)
				{

					if(CharArry[i]==0)
					{
						char* StrBegin = CharArry + StrBeginCount;
						if(i-StrBeginCount != 0)
						{
							TempStrSize = i-StrBeginCount+1;
							if(TempStr==0)
							{
								TempStr = new char[TempStrSize];
								strcpy(TempStr,StrBegin);
							}
							else
							{
								int NewStrSize = i-StrBeginCount+1+TempStrSize;
								char* NewStr = new char[NewStrSize];
								strcpy(NewStr,TempStr);
								char* NewStrMid = NewStr+TempStrSize;
								strcpy(NewStrMid,StrBegin);
								delete TempStr;
								TempStr = NewStr;
								TempStrSize = i-StrBeginCount+1+TempStrSize;
							}
						}
						break;
					}

					if(CharArry[i]==L'\n')
					{
						CharArry[i] = L'\0';
						char* StrBegin = CharArry + StrBeginCount;
						int NewStrSize = i-StrBeginCount+1+TempStrSize;
						char* NewStr = new char[NewStrSize];
						if(TempStrSize!=0)
						{
							strcpy(NewStr,TempStr);
							char* NewStrMid = NewStr+TempStrSize;
							strcpy(NewStrMid,StrBegin);
							delete TempStr;
							TempStr = 0;
							TempStrSize = 0;
						}
						else
						{
							strcpy(NewStr,StrBegin);
						}
						LinePushData( NewStr, NewStrSize, Col, pLine);
						Col++;
						return true;
					}

					int j=0;
					if(CharArry[i] == L'\t' )
					{
						CharArry[i] = L'\0';
						char* StrBegin = CharArry + StrBeginCount;
						int NewStrSize = i-StrBeginCount+1+TempStrSize;
						char* NewStr = new char[NewStrSize];
						if(TempStrSize!=0)
						{
							strcpy(NewStr,TempStr);
							char* NewStrMid = NewStr+TempStrSize;
							strcpy(NewStrMid,StrBegin);
							delete TempStr;
							TempStr = 0;
							TempStrSize = 0;
						}
						else
						{
							strcpy(NewStr,StrBegin);
						}
						LinePushData(NewStr,NewStrSize, Col, pLine);
						Col++;
						StrBeginCount = i+1;
					}
				}
			}
			else
			{
				return false;
			}
		}

		return true;
	}


	bool LoadLineInfo(ExcelTable* pTable,TiXmlNode* pRoot)
	{
		if(!pRoot)
			return false;

		TiXmlNode* LineDefNode	= 0;
		LineDefNode = pRoot->FirstChildElement("line_def");
		if(!LineDefNode)
			return false;

		TiXmlElement* LineDefElement = 0;
		LineDefElement = LineDefNode->FirstChildElement();
		if(!LineDefElement)
			return false;
		for( int i=0 ; LineDefElement; LineDefElement = LineDefElement->NextSiblingElement(),i++ )
		{
			const char* ColType = LineDefElement->Attribute("type");
			int Type = col_type_null;
			if(ColType)
			{
				std::map<std::string, int>::iterator It = ExcelGlobal::Instance().ExcelType.find(ColType);
				if(It != ExcelGlobal::Instance().ExcelType.end())
				{
					Type = It->second;
				}
			}

			pTable->LineInfo.TypeInfo.push_back(Type);
			pTable->LineInfo.IsLoad.push_back(true);

			const char* Option = LineDefElement->Attribute("option");
			if(Option)
			{
				if(std::string(Option)=="key" && pTable->LineInfo.KeyCol ==0 && Type != col_type_null)
				{//option="key"
					pTable->LineInfo.KeyCol = i;
				}

				if(std::string(Option)=="mem" && Type != col_type_null)
				{//option="key"
					pTable->LineInfo.IsLoad[i] = false;
				}
			}
		}

		if(pTable->LineInfo.TypeInfo[pTable->LineInfo.KeyCol ] != col_type_int)
		{
			return false;
		}


		return true;
	}

	bool LoadFile(ExcelTable* pTable,TiXmlNode* pRoot,const std::string& FilePath)
	{
		TiXmlNode* FileNode		= 0;
		FileNode = pRoot->FirstChildElement("file");
		if(!FileNode)
			return false;

		TiXmlElement* FileElement = 0;
		FileElement = FileNode->FirstChildElement();
		if(!FileElement)
			return false;
		int LineIndex = 0;
		for( ; FileElement; FileElement = FileElement->NextSiblingElement() )
		{
			uint32 Top;
			uint32 Bottom;
			bool IsHaveLimit = GetFileLimit(FileElement, Top, Bottom);

			std::string FileName = FileElement->ValueTStr().c_str();

			std::string RelativeFileDir = FilePath+"\\"+FileName+".txt";
			std::string FullFilePath = FileSys::Instance().IntegrateFilePath(EXD,RelativeFileDir);

			FILE* pFile = fopen(FullFilePath.c_str(),"r");
			if(!pFile)
			{
				//log
				continue;
			}

			for(int i=0;!feof(pFile);i++)
			{
				ExcelLine* pLine = new ExcelLine(pTable,LineIndex);
				if(!GetLine(pFile,pLine) || i==0)//��0����˵���У������뵽��������
				{
					delete pLine;
					pLine =NULL;

				}
				else
				{
					if(pTable->LineMap_ID.find(pLine->ID) != pTable->LineMap_ID.end())
					{//������ID�������Ѿ������汻���ع�����ô�������ڶ����
						delete pLine;
						pLine =NULL;
					}
					else
					{
						if(IsHaveLimit)
						{
							if( pLine->ID >= Top && pLine->ID <=Bottom)
							{
								pTable->LineMap_Index.insert(std::pair<uint32, ExcelLine*>(pLine->Index,pLine));//������0��ʼ�����Լ�1
								pTable->LineMap_ID.insert(std::pair<uint32, ExcelLine*>(pLine->ID,pLine));
								LineIndex++;
							}
							else
							{
								delete pLine;
								pLine =NULL;
							}
						}
						else
						{
							pTable->LineMap_Index.insert(std::pair<uint32, ExcelLine*>(pLine->Index,pLine));//������0��ʼ�����Լ�1
							pTable->LineMap_ID.insert(std::pair<uint32, ExcelLine*>(pLine->ID,pLine));
							LineIndex++;
						}
					}
				}
			}

			fclose(pFile);

		}
		return true;
	}

}

ExcelTable::ExcelTable()
{

}

ExcelTable::~ExcelTable()
{
	UnLoadTable();
}


bool ExcelTable::LoadTable(const std::string& FilePath,const std::string& FileName)
{
	std::string XmlRelativeDir;
	if(FilePath.empty())
	{
		XmlRelativeDir = FileName+".xml";
	}
	else
	{
		XmlRelativeDir = FilePath+"\\"+FileName+".xml";
	}
	
	std::string XmlPath = FileSys::Instance().IntegrateFilePath(EXD,XmlRelativeDir);

	TiXmlDocument doc(XmlPath.c_str());
	bool loadOkay = doc.LoadFile();
	if ( !loadOkay )
		return false;

	TiXmlNode* pRoot = 0;

	pRoot = doc.FirstChild( "excel_data" );
	if(!pRoot)
		return false;

	if(!LoadLineInfo(this,pRoot))
		return false;

	if(!LoadFile(this,pRoot,FilePath))
		return false;

	return true;
}

void ExcelTable::UnLoadTable()
{
	std::map<uint32, ExcelLine*>::iterator it = LineMap_Index.begin();
	std::map<uint32, ExcelLine*>::iterator it_end = LineMap_Index.end();
	for(;it!=it_end;it++)
	{
		ExcelLine* pLine = it->second;
		delete pLine;
		pLine =NULL;
	}

	LineMap_Index.clear();
	LineMap_ID.clear();
}

ExcelLine* ExcelTable::Get(uint32 index)
{
	ExcelLine* pLine =NULL;
	std::map<uint32, ExcelLine*>::iterator it = LineMap_Index.find(index);
	if(it!= LineMap_Index.end())
	{
		pLine = it->second;
	}

	return pLine;
}


ExcelLine* ExcelTable::Find(uint32 id)
{
	ExcelLine* pLine =NULL;
	std::map<uint32, ExcelLine*>::iterator it = LineMap_ID.find(id);
	if(it!= LineMap_ID.end())
	{
		pLine = it->second;
	}

	return pLine;
}


int ExcelTable::Size()
{
	return (int)LineMap_ID.size();
}


//--------------------------------------ExcelGlobal--------------------------------


std::map<std::string,int> ExcelGlobal::ExcelType = std::map<std::string,int>();
ExcelGlobal* ExcelGlobal::_inst = NULL;


ExcelGlobal& ExcelGlobal::Instance()
{
	if(_inst==0)
	{
		_inst = new ExcelGlobal;
	}

	return *_inst;
}


ExcelGlobal::ExcelGlobal()
{
	ExcelType.insert( std::pair<std::string, int>("int",col_type_int));
	ExcelType.insert( std::pair<std::string, int>("float",col_type_float));
	ExcelType.insert( std::pair<std::string, int>("text",col_type_text));
	ExcelType.insert( std::pair<std::string, int>("real",col_type_real));
	ExcelType.insert( std::pair<std::string, int>("v_int",col_type_vint));
	ExcelType.insert( std::pair<std::string, int>("v_float",col_type_vfloat));
	ExcelType.insert( std::pair<std::string, int>("v_text",col_type_vtext));
	ExcelType.insert( std::pair<std::string, int>("v_real",col_type_vreal));
}


ExcelGlobal::~ExcelGlobal()
{

}




dn_namespace_end